/*
 * Copyright (c) 2022-2022 Huawei Technologies Co., Ltd. All rights reserved.
 * Copyright (c) 2022-2022 Huawei Device Co., Ltd. All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without modification,
 * are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice, this list of
 *    conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright notice, this list
 *    of conditions and the following disclaimer in the documentation and/or other materials
 *    provided with the distribution.
 *
 * 3. Neither the name of the copyright holder nor the names of its contributors may be used
 *    to endorse or promote products derived from this software without specific prior written
 *    permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
#ifdef LOSCFG_UTS_CONTAINER
#include "los_uts_container.h"
#include "los_config.h"

extern struct ContainerConfig g_containerConfig;
UINT32 g_currentUtsContainerNum = 1;

UtsContainer g_rootUtsContainer;

static UtsContainer *CreateUtsContainer()
{
    if (g_currentUtsContainerNum > g_containerConfig.MaxUtsContainer)
    {
        PRINT_ERR("CreateUtsContainer failed, reach to max container config.\n");
        return NULL;
    }

    UtsContainer *utsContainer = NULL;

    UINT32 size = sizeof(UtsContainer);
    utsContainer = LOS_MemAlloc(m_aucSysMem1, size);

    if (utsContainer == NULL) {
        PRINT_ERR("CreateUtsContainer failed to malloc memory.\n");
        return NULL;
    }

    UINT32 intSave;
    SCHEDULER_LOCK(intSave);
    g_currentUtsContainerNum += 1;
    SCHEDULER_UNLOCK(intSave);

    atomic_set(&utsContainer->count, 1); 
    return utsContainer;
}

static UtsContainer *CreateNewUtsContainer(UtsContainer *runUtsContainer)
{
    UtsContainer *newUtsContainer = NULL;
    unsigned int intSave;

    newUtsContainer = CreateUtsContainer();
    if (newUtsContainer == NULL) {
        PRINT_ERR("newUtsContainer is NULL.\n");
        return NULL;
    }

    ContainerAllocVnum(&(newUtsContainer->containerBase.vnum));

    SCHEDULER_LOCK(intSave);
    memcpy(&newUtsContainer->utsName, &runUtsContainer->utsName, sizeof(newUtsContainer->utsName));
    SCHEDULER_UNLOCK(intSave);

    return newUtsContainer;
}

/*
 * share 父进程UTS容器或者创建新的UTS容器
 */
UtsContainer *HandleUtsContainer(unsigned long flags, UtsContainer *runUtsContainer)
{
    UtsContainer *newUtsContainer = NULL;

    if (!(flags & CLONE_NEWUTS)) {
        GetUtsContainer(runUtsContainer);
        return runUtsContainer;
    }

    newUtsContainer = CreateNewUtsContainer(runUtsContainer);
    if (newUtsContainer == NULL) {
        PRINT_ERR("newUtsContainer is NULL.\n");
        return NULL;
    }

    return newUtsContainer;
}

void FreeUtsContainer(UtsContainer *utsContainer)
{
    LOS_MemFree(m_aucSysMem1, utsContainer);

    UINT32 intSave;
    SCHEDULER_LOCK(intSave);
    g_currentUtsContainerNum -= 1;
    SCHEDULER_UNLOCK(intSave);
}

INT32 ReplaceUtsContainerInBundle(ContainerBundle* bundle, struct UtsContainer *targetUtsContainer)
{
    if (bundle->utsContainer) {
        DerefUtsContainer(bundle->utsContainer);
    }

    bundle->utsContainer = targetUtsContainer;
    GetUtsContainer(targetUtsContainer);

    return LOS_OK;
}

void InitUtsContainer(UtsContainer *utsContainer)
{
    const char *cpuInfo = NULL;
    utsContainer->count = ATOMIC_INIT(1);
    (VOID)strcpy_s(utsContainer->utsName.sysname, sizeof(utsContainer->utsName.sysname), KERNEL_NAME);
    (VOID)strcpy_s(utsContainer->utsName.nodename, sizeof(utsContainer->utsName.nodename), "hisilicon");
    sprintf_s(utsContainer->utsName.version, sizeof(utsContainer->utsName.version), "%s %u.%u.%u.%u %s %s",
        KERNEL_NAME, KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE, __DATE__, __TIME__);
    cpuInfo = LOS_CpuInfo();
    (VOID)strcpy_s(utsContainer->utsName.machine, sizeof(utsContainer->utsName.machine), cpuInfo);
    sprintf_s(utsContainer->utsName.release, sizeof(utsContainer->utsName.release), "%u.%u.%u.%u",
        KERNEL_MAJOR, KERNEL_MINOR, KERNEL_PATCH, KERNEL_ITRE);
    utsContainer->utsName.domainname[0] = '\0';
    ContainerAllocVnum(&(utsContainer->containerBase.vnum));
    return;
}
#endif

